import { createAppAPI } from "./apiCreateApp";

export function createBrowerRendererOption() {
  return {
    createElement: (tag: string): Element => document.createElement(tag),
    setElementText: (el: Element, text: string): void =>
      (el.textContent = text),
    insertChildren: (parent: Element, children: Element): void =>
      parent.appendChild(children),
    patchProps: (vnode, el) => {
      const shouldAsProp = (key, el) => {
        if (el.type === "input" && key === "form") return false;
        return key in el;
      };
      const booleanSet = (el, key, val) => {
        el[key] = val;
        // 针对disabled 属性,如果值为空,则设置为true
        if (val === "") {
          el[key] = true;
        }
      };
      const normalizeClass = (value) => {
        if (!value) {
          return "";
        }

        const values = [];
        if (Array.isArray(value)) {
          value.forEach((item) => {
            values.push(normalizeClass(item));
          });
          return values.join(" ");
        }

        if (typeof value === "object") {
          for (const key in value) {
            if (typeof value[key] === "object") {
              values.push(normalizeClass(value[key]));
            } else if (value[key]) {
              values.push(key);
            }
          }
          return values.join(" ");
        }

        return value;
      };
      const booleanKey = { disabled: true };
      const props = vnode.props;
      for (const key in props) {
        const value = props[key];
        if (key.slice(0, 2) === "on") {
          // 拿到事件名称
          const eventName = key.slice(2).toLowerCase();
          // 获取前元素上的所有的事件
          const invokers = el["_vei"] || (el["_vei"] = {});
          // 获取当前事件的旧事件
          const existingInvoker = invokers[eventName] || {};
          if (value) {
            if (existingInvoker.value) {
              existingInvoker.value = value;
            } else {
              // 创建执行的回调函数
              const invoker = (invokers[eventName] = () => {
                // 从value参数上获取到事件回调函数
                invoker.value.apply(el, arguments);
              });
              // 将用户定义的回调保存到value上,后续更新时,直接调用即可
              invoker.value = value;
              // 增加事件监听
              el.addEventListener(eventName, invoker);
            }
          } else {
            // 移除事件
            el.removeEventListener(eventName, existingInvoker);
            existingInvoker.value = void 0;
          }
        } else if (key === "class") {
          el.className = normalizeClass(value);
        } else if (shouldAsProp(key, el)) {
          if (typeof value === "boolean" || booleanKey[key]) {
            booleanSet(el, key, value);
          } else {
            el[key] = value;
          }
        } else {
          el.setAttribute(key, value);
        }
      }
    },
  };
}

/**
 * 创建符合当前环境的渲染器
 * 内部包括一系列的
 * @returns 返回一个渲染器
 */
export function createContextRenderer(options) {
  const { createElement, setElementText, insertChildren, patchProps } = options;

  const patchElement = (n1, n2, container) => {};
  const patch = (oldVnode, newVnode, container) => {
    if (oldVnode && oldVnode.type !== newVnode.type) {
      unmount(oldVnode);
      oldVnode = null;
    }
    if (typeof newVnode.type === "string") {
      if (oldVnode) {
        // 组件更新
        patchElement(oldVnode, newVnode, container);
      } else {
        // 组件首次挂载
        mountElement(newVnode, container);
      }
    } else {
    }
    // 更新虚拟节点
    container._vnode = newVnode;
  };

  const mountElement = (vnode, container: Element) => {
    const el: Element = createElement(vnode.type);
    if (vnode.props) {
      patchProps(vnode, el);
    }
    if (typeof vnode.children === "string") {
      setElementText(el, vnode.children);
    } else if (Array.isArray(vnode.children)) {
      vnode.children.forEach((ch) => {
        // 首次挂载,旧节点为null
        patch(null, ch, el);
      });
    }
    vnode.el = el;
    insertChildren(container, el);
  };
  const unmount = (vnode) => {
    const parent = vnode.el.parentNode;
    if (parent) {
      parent.removeChild(vnode.el);
    }
  };
  const render = (vnode, container) => {
    if (vnode == null) {
      // 组件卸载
      unmount(container._vnode);
    } else {
      patch(container._vnode, vnode, container);
    }
  };
  return {
    render,
    createApp: createAppAPI(render),
  };
}

export const ensureRenderer = createContextRenderer;
